#include "mainwindow.h"
#include <QString>
#include <QMessageBox>
#include <QClipboard>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    setupUi(this);
    button =pushButton;
    bandWidth = 102400;
    bindHost = "";
    connect(button,SIGNAL(clicked()),this, SLOT(launch()));
}

MainWindow::~MainWindow()
{
}

void MainWindow::tohex(unsigned char& hi, unsigned char& lo, unsigned char from)
{
    hi = from >> 4;
    if(hi > 9)
        hi += 'a' - 10;
    else
        hi += '0';
    lo = from & 0x0f;
    if(lo > 9)
        lo += 'a' - 10;
    else
        lo += '0';
}

unsigned char MainWindow::fromhex(unsigned char hi, unsigned char lo)
{
    if(hi >= 'a')
        hi -= 'a' - 10;
    else
        hi -= '0';
    if(lo >= 'a')
        lo -= 'a' - 10;
    else
        lo -= '0';
    return hi << 4 | lo;
}

void MainWindow::secretKeyProcess(string secretKey)
{
    return ;
}


void MainWindow::launch()
{

    if ( tabWidget->currentIndex() == 0 )
        status = Server;
    else
        status = Client;
    if ( status == Server )
    {
        bool ok;
        bandWidth =bandWidthText->text().toInt(&ok,10);
        listenPort = proxyportText->text().toStdString();
        connectPort = polipoPortText->text().toStdString();
        connectIP = serverIPText->text().toStdString();

    }
    else{
        listenPort = proxyPortText->text().toStdString();
        connectIP = remoteIPText->text().toStdString();
        connectPort = remotePortButton->text().toStdString();
        secrectKey = secretkeyText->text().toStdString();
    }

    if ( listenPort == "" || connectPort == "" || connectIP == "")
    {
        cerr << "FATAL:Options are not enough" << endl;
        exit(1);
    }

    start(listenPort, connectPort, connectIP, status, bandWidth, time(NULL), secrectKey, bindHost);

}


int MainWindow::start(string listenPort,
                      string connectPort,
                      string connectIP,
                      int mode = 1,
                      unsigned int bandWidth = 102400,
                      unsigned int randSeed = 0,
                      string secretKey = "",
                      string bindHost = "")
{

    const size_t keysize = 32;

    boost::shared_array<unsigned char> key(new unsigned char[keysize]);

    if( mode == 1 )
    {

        if(randSeed == 0)
            cerr << "WARN:Random Seed equals zero is not safe when running mode is server.  Please pass the real random seed to the start function." << endl;
        boost::mt19937 rnd;
        rnd.seed(randSeed);
        boost::variate_generator<boost::mt19937&,
                                 boost::uniform_smallint<> > randomizer(rnd, boost::uniform_smallint<>(0, 0x0ff));
        cout << "INFO:Generated Secret Key is:" << endl;
        cout << "INFO:";
        unsigned char hi, lo;
        secretKey = "";
        for(size_t i = 0; i < keysize; ++i)
        {
            key[i] = randomizer();
            tohex(hi, lo, key[i]);
            cout << hi << lo;
            secretKey += hi;
            secretKey += lo;
        }
        cout << endl;
        cout << "INFO:Please send the secret key above to your users." << endl;
        QMessageBox::about ( this, QString("Secret Key:"),QString(secretKey.c_str()));

        secretKeyProcess(secretKey);
    }

    else
    {
        if ( secretKey == "" )
        {
            cerr<< "FATAL:No Serect Key" << endl;
            exit(1);
        };
        for(size_t i = 0; secretKey[i] != '\0' && secretKey[i + 1] != '\0'; i += 2)
            key[i / 2] = fromhex(secretKey[i], secretKey[i + 1]);
    }
    if(bindHost == ""){
        bindHost = ip::host_name();
    }
    try
    {
        io_service io_service;
        SendProxyPtr sendProxy(new SendProxy(io_service, bandWidth));
        sendProxy->start();
        for(ip::tcp::resolver::iterator it = ip::tcp::resolver(io_service).resolve(ip::tcp::resolver_query(bindHost, listenPort)), end; it != end; ++it)
            (new TcpTunnelBuilder<CryptoFactoryPtr, SendProxyPtr>(io_service, it->endpoint(), connectIP, connectPort, CryptoFactoryPtr(new CryptoFactory(key, keysize)), sendProxy))->start();
        io_service.run();
    }
    catch (const exception& e)
    {
        cerr << "FATAL:" << e.what() << endl;
        return -1;
    }
    return 0;
}
